import wx
import gui.posnet_p2p_node_gui
import gui.dialog

import posnet_tcp_client
import posnet_client

import StringIO,pprint,thread,sets,os,sys
from traceback import print_exc




def get_host_port(self):
	""" return host and port entered"""
	try:
		host = self.text_host.GetValue()
		port = int(self.text_port.GetValue())
		return (host,port)
	except Exception,e:
		gui.dialog.show_error(self,'while trying to get host or port\n'+str(e))
	return (None,None)	

def get_deploy_host_port(self):
	""" return host and port entered for deploy"""
	try:
		host = self.deploy_text_host.GetValue()
		port = int(self.deploy_text_port.GetValue())
		return (host,port)
	except Exception,e:
		gui.dialog.show_error(self,'while trying to get deploy-host or deploy-port\n'+str(e))
	return (None,None)	

def get_join_host_port(self):
	""" return host and port entered for deploy"""
	try:
		host = self.join_text_host.GetValue()
		port = int(self.join_text_port.GetValue())
		return (host,port)
	except Exception,e:
		gui.dialog.show_error(self,'while trying to get join-host or join-port\n'+str(e))
	return (None,None)	

def new_poset_learned(self,poset = None):
	if poset is None: poset = dict()
	self.poset = poset
	self.Poset_keys = self.poset.keys()
	self.Poset_keys.sort()
	nb_keys  = len(self.Poset_keys)
	#------------------------------
	comment_poset = "no poset loaded"
	text_poset = "no poset"
	if nb_keys > 0:
		comment_poset = " poset loaded (%d dimensions)" % (nb_keys)
		text_poset = "\n".join( [ ""+str(key[-1]) for key in self.Poset_keys ] )
	self.text_poset.SetValue(text_poset)
	self.comment_poset = wx.StaticText(self.Poset, -1, comment_poset, style=wx.ALIGN_CENTRE|wx.ST_NO_AUTORESIZE)
	#--------------------------------------
	resize_query(self)
	self.tree_ctrl_graph.DeleteAllItems()
	

def handle_refresh_poset(self,event = None):
	""" call hen connect to poset or poset refresh"""  
	host,port= self.get_host_port()
	if host is None: return	
	poset = None
	try:
		self.button_refresh_poset.Enable(False)
		try:
			#-------------------------------------------------------
			poset = posnet_tcp_client.posnet_ping(  (host,port), 0 )
			#---------------------------------------------------------
		except Exception,e:
			error_txt = "while trying to get poset: %s" % (str(e))
			gui.dialog.show_error(self,error_txt)
	finally:
		new_poset_learned(self,poset)	
		self.button_refresh_poset.Enable(True)

def handle_refresh_graph(self,event = None):
	self.tree_ctrl_graph.DeleteAllItems()
	host,port= self.get_host_port()
	if host is None: return	
	try:
		dat = posnet_tcp_client.posnet_state_request(  (host,port), 0 )
		self.text_state.SetValue("ok: "+str(len(dat))+" nodes")	
		root  = self.tree_ctrl_graph.AddRoot(str(host)+":"+str(port))
		#root  = self.tree_ctrl_graph.GetRootItem()
		tosort = []
		for point, data in dat.items():
			tosort.append( (point,data) )
		tosort.sort()
		for point,data in tosort: 
			this_node = self.tree_ctrl_graph.AppendItem(root,",".join( [str(x) for x in point] ))
			self.tree_ctrl_graph.AppendItem(this_node,"State: "+str(data[0]))
			self.tree_ctrl_graph.AppendItem(this_node,"Locked: "+str(data[1]))
		self.tree_ctrl_graph.Expand(root)
	except Exception,e:
		self.text_state.SetValue("error")	
		print_exc()

def handle_connect(self,event):
	host,port= self.get_host_port()
	if host is None: return	
	try:
		self.button_connect.Enable(False)
		handle_refresh_poset(self,event)
		if len(self.Poset_keys) > 0: handle_refresh_graph(self,event)
	finally:
		self.button_connect.Enable(True)

def handle_check(self,event = None):
	""" call hen connect to poset or poset refresh"""  
	host,port= self.get_deploy_host_port()
	if host is None: return	
	poset = None
	try:
		self.button_deploy_check.Enable(False)
		try:
			#-------------------------------------------------------
			poset = posnet_tcp_client.posnet_ping(  (host,port), 0 )
			#---------------------------------------------------------
			self.button_deploy.Enable(False)
			keys = poset.keys()
			keys.sort()
			self.deploy_output.SetValue("overlay node exists\n"+"\n".join( [str(k) for k in keys]  ) )
			self.deploy_nb_dim.SetValue(len(poset))
			return False
		except Exception,e:
			self.deploy_output.SetValue("overlay node does not exist") 
			self.button_deploy.Enable(True)
			return True
	finally:
		self.button_deploy_check.Enable(True)

def handle_check2(self,event = None):
	host,port= self.get_join_host_port()
	if host is None: return	
	poset = None
	try:
		self.button_join_check.Enable(False)
		try:
			#-------------------------------------------------------
			poset = posnet_tcp_client.posnet_ping(  (host,port), 0 )
			#---------------------------------------------------------
			keys = poset.keys()
			keys.sort()
			self.deploy_output.SetValue("overlay node to join exists\n"+"\n".join( [str(k) for k in keys]  ) )
			self.deploy_nb_dim.SetValue(len(poset))
			return True
		except Exception,e:
			self.deploy_output.SetValue("overlay node to join does not exist") 
			return False
	finally:
		self.button_join_check.Enable(True)


def handle_checkbox_join(self,event):
	was_checked = self.checkbox_join.IsChecked()
	valid_join = False
	if was_checked: 
		valid_join = handle_check2(self,event)
		if not valid_join: self.checkbox_join.SetValue(False)
	if valid_join:
		self.deploy_nb_dim.Enable(False)
	else:
		self.deploy_nb_dim.Enable(True)


def handle_deploy(self,event):
	try:
		self.button_deploy.Enable(False)
		try:
			valid_destination = handle_check(self,event)
			if not valid_destination:
				raise Exception("Invalid overlay node to deploy")
			has_join =  handle_checkbox_join(self,event)
			ssh_user = self.text_deploy_login.GetValue().strip()
			#ssh_password = self.text_deploy_password.GetValue().strip() 		
			overlay_node_host = self.deploy_text_host.GetValue()
			overlay_node_port =  self.deploy_text_port.GetValue()	
			path_to_server = self.text_deploy_path.GetValue()
			if len(path_to_server.strip()) == 0: 
				raise Exception("Invalid path to pyposnet")
			command = "nohup python %s %s"  % (path_to_server.strip(),overlay_node_port)
			if has_join: command += " "+self.join_text_host.GetValue()+" "+str(self.join_text_port.GetValue())
			ssh_command = "ssh "
			if len(ssh_user) > 0: ssh_command+= " -l"+ssh_user+" " 	
			ssh_command += " "+overlay_node_host
			cmd = ssh_command+" "+command #" \\> "+path_to_server+"."+str(overlay_node_port)+".info 2\\> "+path_to_server+"."+str(overlay_node_port)+".error \""
			print cmd 
			fd = os.popen(cmd)
			output  =fd.read()
			fd.close()
			#output = ssh_functions.runssh(command,host=overlay_node_host, user=ssh_user,  password=ssh_password) 
			self.deploy_output.SetValue(output)
		except Exception,e:
			gui.dialog.show_error(self,'while trying to deploy\n'+str(e))
	finally:
		self.button_deploy.Enable(True)
			

def resize_query(self):
	#	Container  = self.Query.GetSizer().GetChildren()[0].GetSizer().GetChildren()
	Container = self.Query.GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetSizer()
	Container.Clear(1)
	del self.query_comp[:]
	if False:	
		length =  len(Container.GetChildren())	
		index = length - 1
		while index > 0:
			Container.Detach(index)
			index = index - 1
		print Container.GetChildren()
		import sys
		sys.stdout.flush()
		Container.Layout()
	poset_len = len(self.Poset_keys)
        #self.button_send_query = wx.Button(self.Query, -1, "send query")
        #self.Bind(wx.EVT_BUTTON, self.handle_query, self.button_send_query)
       	#Container.Add(self.button_send_query, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 0)

	for x in xrange(poset_len):
		query_comp = wx.TextCtrl(self.Query, -1, "")
		query_comp.SetValue("<value for '"+str(self.Poset_keys[x][-1])+"'>")
		self.query_comp.append(query_comp)
		Container.Add(query_comp,0,0,0)
	Container.Layout()
	self.Query.Layout()	

def get_query_point(self):
	val_array = []
	index = 0
	for q in self.query_comp:
		index += 1
		try:
			i = int(q.GetValue())
			val_array.append(i)	
		except ValueError:
			raise Exception("cannot parse point, at "+str(index)+"th : "+str(q.GetValue()))
	return val_array

def handle_query(self,event):
	thread.start_new_thread(handle_query_threaded,(self,))

def handle_insert(self,event):
	try:
		try:
			self.button_insert.Enable(False)
			handle_insert_threaded(self)
		finally:	
			self.button_insert.Enable(True)
	except Exception,e:
		gui.dialog.show_error(self,'while inserting\n'+str(e))
		
	#thread.start_new_thread(handle_insert_threaded,(self,))

def handle_insert_threaded(self,event = None):
	is_random = self.checkbox_insert_random.GetValue()
	host,port= self.get_host_port()
	bound_min = 0
	bound_max = 1000
	if not is_random:
		point = get_query_point(self)
		posnet_tcp_client.posnet_add_handle( (host,port),  point, '')
	else:
		number = int(self.nb_random.GetValue())
		#if cmd == "bulkaddrandom": number = int( arg )	
		for iter in xrange(number): posnet_tcp_client.posnet_add_random_handle_range( (host,port), self.Poset_keys, bound_min, bound_max)


	
def handle_query_threaded(self,event = None):
	cmd  =  self.combo_box_query_algorithms.GetStringSelection()
	host,port= self.get_host_port()
	self.query_result.Clear()
	try:	
		if cmd == "all_top":
			solutions = sets.Set()
			for ack_msg in  posnet_tcp_client.posnet_point_query( (host,port) ,"all_top (Point query)",None ):
				for sol in ack_msg.data.results: solutions.add( (ack_msg.source,tuple(sol)) )
			sio = StringIO.StringIO()
			try:	
				for node,sol in solutions:
					print >>sio,node,",".join( [str(i) for i in sol ] )
				self.query_result.AppendText(sio.getvalue())
			finally: sio.close()
		#elif cmd in point_queries:	
		else:
			solutions = sets.Set()
			point = get_query_point(self)
			sio = StringIO.StringIO()
			try:	
				for ack_msg in  posnet_tcp_client.posnet_point_query( (host,port) ,cmd+" (Point query)" ,point ):
					for sol in ack_msg.data.results:
						solutions.add( (ack_msg.source,tuple(sol)) )
				for node,sol in solutions:
					print >>sio,node,",".join( [str(i) for i in sol ] )
				self.query_result.AppendText(sio.getvalue())
			finally: sio.close()
	except Exception,e:
		gui.dialog.show_error(self,'while procesing query"'+str(cmd)+'"\n'+str(e))


#-------------------------------------------
# Handlers (functions called by gui action)
# Graph drawings
#--------------
import Image
import ImageChops
def autocrop(im, bgcolor):
	if im.mode != "RGB":
		im = im.convert("RGB")
	bg = Image.new("RGB", im.size, bgcolor)
	diff = ImageChops.difference(im, bg)
	bbox = diff.getbbox()
	if bbox:
		return im.crop(bbox)
	return None # no contents


def make_image(orig_path,graphic_path):
	if os.path.exists(orig_path):
		im1 = Image.open(orig_path)		
		x,y = im1.size
		width = 600
		height = 600
		if x > y:
			height = int( float(y) * 600.0/float(x) ) 
		else:
			width = int( float(x) * 600.0/float(y) ) 
		try: im1 = autocrop(im1,"white")	
		except: pass	
		im5 = im1.resize((width, height) , Image.BICUBIC) 	
		im5.save( graphic_path)
		print >>sys.stderr,"IMAGE:",graphic_path
	else: 
		if os.path.exists(graphic_path):
			os.remove(graphic_path)
	
def handle_draw(self,event):
	host,port= self.get_host_port()
	try:
		self.button_draw.Enable(False)
		try:
			outname = ""
			outdir = os.path.join(os.path.split(sys.argv[0])[0],"guidraw")
			posnet_tcp_client.posnet_draw_topology((host,port),outdir,outname,self.poset)	
			#----------------
			orig_path = os.path.join( outdir,"semantic_graph_algo5.png")
			ipath = os.path.join( outdir,"resized_semantic_graph_algo5.png")
			#orig_path  = os.path.join( os.path.split(sys.argv[0])[0], outdir,name)
			make_image(orig_path,ipath)
			if not os.path.exists(ipath):
				self.bitmap_semantic_graph.SetBitmap(wx.Bitmap(orig_path, wx.BITMAP_TYPE_ANY))
			else:
				self.bitmap_semantic_graph.SetBitmap(wx.Bitmap(ipath, wx.BITMAP_TYPE_ANY))
			#----------------
			orig_path = os.path.join( outdir,"overlay.png")
			ipath = os.path.join( outdir,"resized_overlay.png")
			#orig_path  = os.path.join( os.path.split(sys.argv[0])[0], outdir,name)
			#make_image(orig_path,ipath)
			if not os.path.exists(ipath):
				self.bitmap_overlay_graph.SetBitmap(wx.Bitmap(orig_path, wx.BITMAP_TYPE_ANY))
			else:
				self.bitmap_overlay_graph.SetBitmap(wx.Bitmap(ipath, wx.BITMAP_TYPE_ANY))
			#----------------
			orig_path = os.path.join( outdir,"semantic_graph.png")
			ipath = os.path.join( outdir,"resized_semantic_graph.png")
			#orig_path  = os.path.join( os.path.split(sys.argv[0])[0], outdir,name)
			make_image(orig_path,ipath)
			if not os.path.exists(ipath):
				self.bitmap_posnet_graph.SetBitmap(wx.Bitmap(orig_path, wx.BITMAP_TYPE_ANY))
			else:
				self.bitmap_posnet_graph.SetBitmap(wx.Bitmap(ipath, wx.BITMAP_TYPE_ANY))
		except Exception,e:
			print e
			sys.stdout.flush()
			raise
	finally:
		self.button_draw.Enable(True)
class my_img:
	outdir = os.path.join(os.path.split(sys.argv[0])[0],"guidraw")
	def __init__(self,name,ext,na = None):
		self.name = name
		self.ext = ext
		if na is None: self.filename = name+"."+ext
		else: self.filename= na
		self.dirname = ''
	def GetValue(self):
		f = file(os.path.join(my_img.outdir,self.name+"."+self.ext),"rb") 
		try: return f.read()
		finally: f.close()


def handle_save_semantic_graph(self,event):
	gui.dialog.Save(self,event,my_img("semantic_graph_algo5","png","semantic_graph.png"),"semantic_graph","png")
	gui.dialog.Save(self,event,my_img("semantic_graph_algo5","dot","semantic_graph.dot"),"semantic_graph","dot")

def handle_save_overlay_graph(self,event):
	gui.dialog.Save(self,event,my_img("overlay","png","overlay_graph.png"),"overlay_graph","png")
	gui.dialog.Save(self,event,my_img("overlay","dot","overlay_graph.dot"),"overlay_graph","dot")


def handle_save_posnet_graph(self,event):
	gui.dialog.Save(self,event,my_img("semantic_graph","png","posnet_graph.png"),"posnet_graph","png")
	gui.dialog.Save(self,event,my_img("semantic_graph","dot","posnet_graph.dot"),"posnet_graph","dot")

def handle_save_points(self,event):
	gui.dialog.Save(self,event,my_img("points","tsv"),"points","tsv")


def fill_query_algorithms(self):
	point_queries = posnet_client.posnet_client_algorithms_zero_args()
	for point_query in point_queries:
		self.combo_box_query_algorithms.Append(point_query)
	point_queries = posnet_client.posnet_client_algorithms_one_args()
	for point_query in point_queries:
		self.combo_box_query_algorithms.Append(point_query)

class overlay_node_app(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers()
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_connect",handle_connect)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_query",handle_query)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_draw",handle_draw)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_insert",handle_insert)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_refresh_poset",handle_refresh_poset)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_refresh_graph",handle_refresh_graph)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"get_host_port",get_host_port)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"get_deploy_host_port",get_deploy_host_port)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"get_join_host_port",get_join_host_port)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_save_semantic_graph",handle_save_semantic_graph)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_save_posnet_graph",handle_save_posnet_graph)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_save_overlay_graph",handle_save_overlay_graph)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_save_points",handle_save_points)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_check",handle_check)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_check2",handle_check2)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_checkbox_join",handle_checkbox_join)
	setattr(gui.posnet_p2p_node_gui.posnet_overlay_node_frame,"handle_deploy",handle_deploy)
        main_frame = gui.posnet_p2p_node_gui.posnet_overlay_node_frame(None, -1, "")
        self.SetTopWindow(main_frame)
	#-------------------------------
	# set attributes to the gui frame
	names =  {  "poset" : dict(), "Poset_keys":[], \
			# "Query":dict(), \
			"Insert":dict(), "Draw":dict(), "query_comp" : [], "button_send_query":None}
	for name,def_val in names.items():
		#obj = getattr(  main_frame  ,name)
		#for y in ("filename","dirname"):
		#	setattr(obj,y,"")
		#setattr(obj,name,def_val)
		setattr(main_frame,name,def_val)
	fill_query_algorithms(main_frame)
        main_frame.Show()
        return 1

# end of class posnet_overlay_node_app

if __name__ == "__main__":
	posnet_overlay_node_gui = overlay_node_app(0)
	posnet_overlay_node_gui.MainLoop()
